<?php
class ZeusLib_Resource_Xml_Parser
{

	/**
	 * Encoding for xml files.
	 * Must be set separate because configs sometimes cannot be used at this time.
	 *
	 * @var String
	 */
	const ENCODING = 'UTF-8';

	/**
	 * Root element of the xml element list
	 *
	 * @var ZeusLib_Xml_Element
	 */
	private $rootElement;


	/**
	 * Load a xml file and create a object list beginning with the element that can be get by getRootElement()
	 *
	 * @param String $path
	 */
	public function load($path)
	{
		// Check whether the given path is a xml file
		if(!ZeusLib_Helper_File::isXmlFile($path))
		{
			// Throw new exception
			throw new Exception('File must be a xml file: '.$path);
		}

		// Create new xml reader object
		$xmlObject = new XMLReader();

		// Open the given url
		$xmlObject->open($path, self::ENCODING);

		// Check whether the xml document is valid
		// TODO: never valid?
		if(false && $xmlObject->isValid())
		{
			// Throw new exception
			throw new Exception('Xml document is not valid.');
		}

		// Move cursor to first element
		$xmlObject->read();

		// Get the dom object
		$domNode = $xmlObject->expand();

		// Start the recusion
		$this->loadRecursion($domNode);
	}

	/**
	 * Do the recursion to create the xml elements
	 *
	 * @param DOMNode $domNode
	 * @param ZeusLib_Xml_Element $parent
	 */
	private function loadRecursion($domNode, $parent = null)
	{
		// Check whether we got an element object
		if($domNode->nodeType == XMLReader::ELEMENT)
		{
			// Create and xml element object and set the data
			$xmlElement = new ZeusLib_Resource_Xml_Collection_Element();
			$xmlElement->setName($domNode->nodeName);

			// Iterate attributes
			foreach($domNode->attributes as $attribute)
			{
				// Append the attribute cache
				$xmlElement->setAttribute($attribute->name, $attribute->value);
			}

			// Check whether this is the first element and so has no parent
			if($parent === null)
			{
				// Set the root element
				$this->rootElement = $xmlElement;
			}
			// This is not the first element
			else
			{
				// Set the associations between parent and active object
				$xmlElement->setParent($parent);
				$parent->addChild($xmlElement);
			}

			// Check whether there are some children
			if($domNode->hasChildNodes())
			{
				// Iterate all children
				foreach($domNode->childNodes as $childNode)
				{
					// Start the recursion with every child
					$this->loadRecursion($childNode, $xmlElement);
				}
			}
		}

		// Check whether we got a cdata or text object object
		if($domNode->nodeType == XMLReader::CDATA || $domNode->nodeType == XMLReader::TEXT)
		{
			// Get the trimmed data
			$data = trim($domNode->data);

			// Check whether the data is not emptry
			if(!empty($data))
			{
				// Set the data to the parent object
				$parent->setValue($data);
			}
		}
	}

	/**
	 * Returns the root element for this parser.
	 *
	 * @return ZeusLib_Xml_Element
	 */
	public function getRootElement()
	{
		// Returl variable
		return $this->rootElement;
	}

}